package com.ftg.learn.Config;

import com.alibaba.fastjson.JSON;
import com.alibaba.nacos.api.NacosFactory;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.listener.Listener;
import com.alibaba.nacos.api.exception.NacosException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.context.annotation.DependsOn;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.Executor;

/**
 *  gateway初始化 路由，路由信息从nacos里获取。
 *   1.里面的方法包含，初始化路由
 *   2.当路由发生变化时的监听操作
 * @author Guo
 * @date 2022/3/28
 */
@Component
@Slf4j
@DependsOn(value = {"nacosBaseInfo"})
public class GatewayInitByNacos {

    @Autowired
    private GatewayRouteImp gatewayRouteImp;

    private ConfigService configService;

    @PostConstruct
    public void init() {
        log.info("gateway route init...");
        try{
            //创建了一个可以与nacos config进行通信的服务器
            configService = initConfigService();
            if(configService == null){
                log.warn("initConfigService fail");
                return;
            }
            String configInfo = configService.getConfig(NacosBaseInfo.NACOS_ROUTE_DATA_ID,
                    NacosBaseInfo.NACOS_ROUTE_GROUP,
                    NacosBaseInfo.DEFAULT_TIMEOUT);
            log.info("获取网关当前配置:\r\n{}",configInfo);
            List<RouteDefinition> definitionList = JSON.parseArray(configInfo, RouteDefinition.class);
            for(RouteDefinition definition : definitionList){
                log.info("update route : {}",definition.toString());
                gatewayRouteImp.add(definition);
            }
        } catch (Exception e) {
            log.error("初始化网关路由时发生错误",e);
        }
        //为了远程的网关配置(nacos config)里面进行修改以后的操作
        dynamicRouteByNacosListener(NacosBaseInfo.NACOS_ROUTE_DATA_ID,NacosBaseInfo.NACOS_ROUTE_GROUP);
    }

    /**
     * 监听Nacos下发的动态路由配置
     * @param dataId
     * @param group
     */
    public void dynamicRouteByNacosListener (String dataId, String group){
        try {
            //用来监听nacos服务上面的某一个特定配置集
            //String dataId (配置集), String group(分组), Listener listener 监听实现类
            configService.addListener(dataId, group, new Listener()  {
                //如果我接收到配置信息(nacos config)
                @Override
                public void receiveConfigInfo(String configInfo) {
                    log.info("进行网关更新:\n\r{}",configInfo);
                    //JSON 这是json类
                    //目标是什么 configInfo 转换成 routedefinition集体
                    //configInfo -- 说法是nacos config 里面你配置的信息 (json)
                    List<RouteDefinition> definitionList = JSON.parseArray(configInfo, RouteDefinition.class);
                    log.info("update route : {}",definitionList.toString());
                    //实现将修改routes然后通过事件发送机配置将这个事件发送给gateway，gateway里面多一个事件（配置routes）
                    gatewayRouteImp.updateList(definitionList);
                }
                @Override
                public Executor getExecutor() {
                    log.info("getExecutor\n\r");
                    return null;
                }
            });
        } catch (NacosException e) {
            log.error("从nacos接收动态路由配置出错!!!",e);
        }
    }

    /**
     * 初始化网关路由 nacos config
     * @return nacos服务
     */
    private ConfigService initConfigService(){
        try{
            Properties properties = new Properties();
            properties.setProperty("serverAddr",NacosBaseInfo.NACOS_SERVER_ADDR);
            properties.setProperty("namespace",NacosBaseInfo.NACOS_NAMESPACE);
            return configService= NacosFactory.createConfigService(properties);
        } catch (Exception e) {
            log.error("初始化网关路由时发生错误",e);
            return null;
        }
    }
}